package com.atguigu.spzx.manager.service.impl;

import com.atguigu.spzx.common.exception.GuiguException;
import com.atguigu.spzx.common.util.LoginAuthUtil;
import com.atguigu.spzx.manager.mapper.SysMenuMapper;
import com.atguigu.spzx.manager.mapper.SysRoleMenuMapper;
import com.atguigu.spzx.manager.service.SysMenuService;
import com.atguigu.spzx.model.entity.system.SysMenu;
import com.atguigu.spzx.model.entity.system.SysUser;
import com.atguigu.spzx.model.vo.common.ResultCodeEnum;
import com.atguigu.spzx.model.vo.system.MenuVo;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class SysMenuServiceImpl implements SysMenuService {
    @Resource
    SysMenuMapper sysMenuMapper;
    @Resource
    SysRoleMenuMapper sysRoleMenuMapper;
    @Override
    public List<SysMenu> listMenus() {
        //父子菜单数据都是menu表中的数据，可以查询所有，在代码中组装数据
        List<SysMenu> menus = sysMenuMapper.selectAllMenus();
        //查询一级父菜单: 如果一个menu的parentid为0 表示它是父菜单
        List<SysMenu> parents = menus.stream().filter(sysMenu -> sysMenu.getParentId().longValue() == 0).collect(Collectors.toList());
        //再遍历父菜单 查询每个父菜单的子菜单集合绑定
        buildMenuTree(parents , menus); //最终所有的菜单级联关系的数据都绑定到一级菜单上
        // 查询1级菜单集合，一级菜单的子菜单集合遍历时，每个子菜单可能还有下一级
        return parents;
    }

    private void buildMenuTree(List<SysMenu> parents, List<SysMenu> menus) {
        if(CollectionUtils.isEmpty(parents) || CollectionUtils.isEmpty(menus)){
            //父菜单集合 和所有菜单集合不能为空
            return;
        }
        //遍历父菜单集合
        parents.forEach(parent ->{
            //parent表示一个父菜单
            //根据parent的id 查找自己的下一级(如果一个menu的parentId=parent的id 就满足要求)
            List<SysMenu> children = menus.stream().filter(menu -> parent.getId().longValue() == menu.getParentId().longValue()).collect(Collectors.toList());
            parent.setChildren(children);
            //再给children挑选它的下一级的子菜单集合
            buildMenuTree(children , menus);
        });

    }


    @Override
    public void deleteById(Long id) {
        //检查id对应的菜单是否有下一级
        long count = sysMenuMapper.selectChildCount(id);
        if(count>0){
            throw new GuiguException(ResultCodeEnum.HAS_CHILDREN_ERROR);
        }
        sysMenuMapper.deleteById(id);
    }

    @Override
    public SysMenu getById(Long id) {
        return sysMenuMapper.getById(id);
    }

    @Override
    public void updateById(SysMenu sysMenu) {
        sysMenu.setUpdateTime(new Date());
        sysMenuMapper.updateById(sysMenu);
    }

    @Override
    public void save(SysMenu sysMenu) {
        sysMenu.setCreateTime(new Date());
        sysMenu.setUpdateTime(new Date());
        sysMenuMapper.save(sysMenu);
    }

    @Override
    public Map<String, Object> listRoleMenus(Long roleId) {
        //1、查询所有可用的菜单
        List<SysMenu> menus = sysMenuMapper.selectAllMenus().stream()
                .filter(sysMenu -> sysMenu.getStatus().intValue() == 1)
                .collect(Collectors.toList());
        //2、组装为父子菜单集合
        List<SysMenu> parents = menus.stream().filter(sysMenu -> sysMenu.getParentId().longValue() == 0).collect(Collectors.toList());
        buildMenuTree(parents,menus);
        //3、查询角色已分配的菜单id集合： 操作sys_role_menu表
        //自定义bean  mapper
        List<Long> checkedMenuIds = sysRoleMenuMapper.selectCheckedMenuIdsByRoleId(roleId);
        Map<String, Object> map = new HashMap<>();
        map.put("menus",parents);
        map.put("checkedMenuIds",checkedMenuIds);
        return map;
    }

    @Override
    public List<MenuVo> listMenusByLoginUserId() {
        //1、获取登录用户的id
        SysUser sysUser = LoginAuthUtil.get();
        //2、查询当前用户的角色拥有的菜单列表封装为MenuVo对象的嵌套集合
        /*
            sys_user
                sys_user_role
            sys_role
                sys_role_menu
            sys_menu : 最终要查询用户的菜单

            先根据用户id查询sys_user_role表中 已分配的角色id
            再根据角色id到sys_role_menu表中查询 已分配的菜单id(如果需要考虑菜单是否被禁用)
            使用菜单id到sys_menu表中查询 菜单

         */
        //因为数据需要组装为父子关系的集合  查询的数据必须携带parent_id
        List<SysMenu> sysMenus =  sysMenuMapper.selectMenusByLoginUserId(sysUser.getId());
        //只组装1级和2级 菜单
        List<MenuVo> parents = sysMenus.stream()
                //使用parentId字段的值挑选一级菜单(一级菜单parentId为0)
                .filter(sysMenu -> sysMenu.getParentId().longValue() == 0)
                //如果数据集合 每个元素需要转为 另一个类型的值/对象  可以使用map处理
                .map(parent -> { //封装1级菜单对象
                    MenuVo menuVo = new MenuVo();
                    menuVo.setName(parent.getComponent());
                    menuVo.setTitle(parent.getTitle());
                    //使用一级菜单的id当做父id从sysMenus中查询它的下一级菜单集合
                    List<MenuVo> children = sysMenus.stream()
                            .filter(child -> child.getParentId().longValue() == parent.getId().longValue())
                            .map(child -> {
                                MenuVo childMenuVo = new MenuVo();
                                childMenuVo.setChildren(null);
                                childMenuVo.setName(child.getComponent());
                                childMenuVo.setTitle(child.getTitle());
                                return childMenuVo;
                            }).collect(Collectors.toList());
                    menuVo.setChildren(children);
                    //返回一个组装好的一级菜单和他嵌套的二级菜单集合 的对象
                    return menuVo;
                })
                //将map返回的每个一级菜单对象 封装到List集合中
                .collect(Collectors.toList());


        return parents;
    }
}
